#pragma once

#include <string>
#include <sstream>
#include <vector>
#include <list>
#include <type_traits>
#include <memory>

using namespace std;

#define rep(a,b,c) for(int a=b;a<=c;a++)
#define red(a,b,c) for(int a=b;a>=c;a--)

class DataStream {
public:
	DataStream();
	DataStream(const char * Src, int Size, bool copy = true);
	DataStream(const string & Src, bool copy = true);//TODO:ignore copy param
	~DataStream();
	void DoString(string & Str);
	template<class C>
	void DoList(list<C> & Src)
	{
		int cnt = 0;
		C tmp;
		string tmp2;

		if (IsRead)
		{
			Src.clear();
			DoObj<int>(cnt);
			if (is_same<C, string>::value)
			{
				rep(i, 0, cnt - 1)
				{
					DoString(tmp2);
					((list<string>&)Src).push_back(tmp2);
				}
			}
			else
			{
				rep(i, 0, cnt - 1)
				{
					DoObj<C>(tmp);
					Src.push_back(tmp);
				}
			}
		}
		else
		{
			cnt = Src.size();
			DoObj<int>(cnt);
			if (is_same<C, string>::value)
			{
				for (string & sub : ((list<string>&)Src)) {
					DoString(sub);
				}
			}
			else
			{
				for (C & sub : Src) {
					DoObj<C>(sub);
				}
			}
		}
	}
	template<class C>
	void DoObj(C & data)
	{
		if (IsRead)
		{
			if (is_same<C, string>::value)
			{
				DoString((string&)data);
			}
			else
			{
				in_ios.read((char*)(&data), sizeof(data));
			}
		}
		else
		{
			if (is_same<C, string>::value)
			{
				DoString((string&)data);
			}
			else
			{
				in_ios.write((char*)(&data), sizeof(data));
			}
		}
	}
	template<class C>
	void DoObjEx(C & Src, int Size)
	{
		if (IsRead)
		{
			in_ios.read((char*)(&Src), Size);
		}
		else
		{
			in_ios.write((char*)(&Src), Size);
		}
	}
	template<class C>
	void DoVector(vector<C>& Src)
	{
		int cnt = 0;
		C tmp;
		string tmp2;

		if (IsRead)
		{
			Src.clear();
			DoObj<int>(cnt);
			if (is_same<C, string>::value)
			{
				rep(i, 0, cnt - 1)
				{
					DoString(tmp2);
					((vector<string>&)Src).push_back(tmp2);
				}
			}
			else
			{
				rep(i, 0, cnt - 1)
				{
					DoObj<C>(tmp);
					Src.push_back(tmp);
				}
			}
		}
		else
		{
			cnt = Src.size();
			DoObj<int>(cnt);
			if (is_same<C, string>::value)
			{
				rep(i, 0, cnt - 1)
				{
					DoString(((vector<string>&)Src).at(i));
				}
			}
			else
			{
				rep(i, 0, cnt - 1)
				{
					DoObj<C>(Src.at(i));
				}
			}
		}
	}
	int Size();
	void Clear();
	string GetSrc();//TODO:unsafe
	const char * GetCCS();
	void PutFrom(const char * Src, int Size, bool copy=true);//重定向流指针
	void PutFrom(const string & Src);//WARN:must use &  because it may be copyed by stop from /0
	//int CopyTo(char ** output);  //ERROR:unsafe
	int CopyTo(string &output);
	void ChangeMode(bool IsRead_);
	bool GetMode();
	void SetPoint(int p=0);
private:
	stringstream in_ios;
	bool IsRead;
};
